﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace Objects.Tags
{
    /// <summary>
    /// Имена классов
    /// </summary>
    public class Tags<Tkey, Tvalue>
    {
        protected Tags() { }
        private static Dictionary<Tkey, Tvalue> tags = new Dictionary<Tkey, Tvalue>();
        /// <summary>
        /// Имя экземпляра
        /// </summary>
        public static Tvalue Get(Tkey type)
        {
            Tvalue tag = default(Tvalue);
            if (!type.IsEquals(default(Tkey)) && !tags.TryGetValue(type, out tag))
                tag = DefaultTags<Tkey, Tvalue>.Get(type);
            return tag;

        }
        public static IEnumerable<Tkey> GetKeyFromValue(Tvalue value)
        {
            foreach (var item in tags)
                if (item.Value.IsEquals(value))
                    yield return item.Key;
        }
        public static void AddOrGen(Tkey type, Tvalue tag)
        {
            GetOrGen(type, tag);
        }
        public static Tvalue GetOrGen(Tkey type, Tvalue tag)
        {
            return GetOrSet(type, (tag.IsEquals(default(Tvalue))) ? DefaultTags<Tkey, Tvalue>.Get(type) : tag);
        }
        public static void AddOrSet(Tkey type, Tvalue tag)
        {
            if (type != null)
                tags.AddOrSetValue(type, tag);
        }
        public static Tvalue GetOrSet(Tkey type, Tvalue tag)
        {
            if (!type.IsEquals(default(Tkey)))
                return tags.GetOrAddDefault(type, tag);
            else
                return default(Tvalue);
        }
        public static Tvalue GetOrGen(Tkey type)
        {
            return GetOrGen(type, default(Tvalue));
        }
        public static void AddOrSet(Tkey type)
        {
            AddOrGen(type, default(Tvalue));
        }
    }

    internal static class DefaultTags<Ttype, Ttag>
    {
        public static Func<Ttype, Ttag> GetDefaultFunc;

        public static Ttag Get(Ttype type)
        {
            if (GetDefaultFunc != null)
                return GetDefaultFunc(type);
            else
                return default(Ttag);
        }
    }

    /// <summary>
    /// Счетчик
    /// </summary>    
    public static class Counter
    {
        private static Dictionary<Type, int> numbers = new Dictionary<Type, int>();
        public static int Next(Type type)
        {
            int i = 0;
            if (type != null)
                if (numbers.ContainsKey(type))
                    i = ++numbers[type];
                else
                    numbers.Add(type, ++i);
            else
                i = -1;
            return i;
        }
        public static int Current(Type type)
        {
            int i = 0;
            if (type != null)
                numbers.TryGetValue(type, out i);
            else
                i = -1;
            return i;
        }
    }

    /// <summary>
    /// Счетчик
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static class Counter<T>
    {
        public static int Next()
        {
            return Counter.Next(typeof(T));
        }
        public static int Current
        {
            get { return Counter.Current(typeof(T)); }
        }
    }
    /// <summary>
    /// Автоматический генератор имен
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static class NameGen<T>
    {
        static NameGen()
        {
            NameGen.Add(typeof(T));
        }
        public static string Get()
        {
            return NameGen.Get(typeof(T));
        }
    }

    public static class NameGen
    {
        private static Dictionary<Type, string> names = new Dictionary<Type, string>();
        private static Dictionary<Type, string> templates = new Dictionary<Type, string>();
        public static void Add(Type type)
        {
            Add(type, string.Empty, string.Empty);
        }
        public static void Add(Type type, string name)
        {
            Add(type, name, string.Empty);
        }
        public static void Add(Type type, string name, string template)
        {
            if (type != null)
            {
                names.AddOrSetValue(type, CName.GetOrGen(type, name));
                templates.GetOrAddDefault(type, "{0}-{1}");
            }
        }
        private static string GetOrGen(Type type)
        {
            string name = string.Empty;
            if (type != null)
                if (names.TryGetValue(type, out name))
                    return name;
                else
                {
                    Add(type);
                    if (names.TryGetValue(type, out name))
                        return name;
                }
            return name;
        }
        private static string GetOrGenTemplate(Type type)
        {
            string template = string.Empty;
            if (type != null)
                if (templates.TryGetValue(type, out template))
                    return template;
                else
                {
                    Add(type);
                    if (templates.TryGetValue(type, out template))
                        return template;
                }
            return template;
        }
        public static string GetTemplate(Type type)
        {
            return GetOrGenTemplate(type);
        }
        public static string Get(Type type)
        {
            return GetTemplate(type).goFormat(CName.GetOrGen(type), Counter.Next(type));
        }
    }
}
